package xipujewel.xipujewel.service.common;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import net.esoar.modules.persistence.FilterUtil;
import net.esoar.modules.utils.DateProvider;
import net.esoar.modules.web.pojo.JPage;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.transaction.annotation.Transactional;

import xipujewel.xipujewel.entity.IdEntity;
import xipujewel.xipujewel.entity.OperateEntity;
import xipujewel.xipujewel.exceptions.ServiceException;
import xipujewel.xipujewel.repository.JpaDao;
import xipujewel.xipujewel.utils.UserUtil;

/**
 * Service层基类，实现一些公有的操作
 * 
 * @author chenling
 * 
 * @param <E>
 * @param <D>
 */
@Transactional(readOnly = true)
public abstract class JpaManager<E extends IdEntity, D extends JpaDao<E>> {

	@PersistenceContext
	protected EntityManager entityManager;

	private Class<E> genericClassE = getClazz();

	protected Logger logger = LoggerFactory.getLogger(getClazz());

	protected abstract D getDao();

	/** 统一时间提供类 */
	protected DateProvider dateProvider = DateProvider.DEFAULT;

	public void setDateProvider(DateProvider dateProvider) {
		this.dateProvider = dateProvider;
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	protected Class<E> getClazz() {
		Type genericSuperclass = getClass().getGenericSuperclass();
		if (genericSuperclass instanceof Class) {
			return (Class<E>) ((ParameterizedType) ((Class) genericSuperclass).getGenericSuperclass())
					.getActualTypeArguments()[0];
		} else if (genericSuperclass instanceof ParameterizedType) {
			return (Class<E>) ((ParameterizedType) genericSuperclass).getActualTypeArguments()[0];
		}

		return null;
	}

	public E get(final Long id) {
		E entity = getDao().findOne(id);
		if (null == entity) {
			try {
				entity = genericClassE.newInstance();
				entity.setId(0L);
			} catch (InstantiationException e) {
				logger.error("通过泛型实例化实体出错!" + e.toString());
			} catch (IllegalAccessException e) {
				logger.error("通过泛型实例化实体出错!" + e.toString());
			}
		}
		return entity;
	}

	/**
	 * 批量保存实体
	 * 
	 * @param entitys
	 * @param numberOfBatch
	 *            多少条数量批次一次,默认30,如果数据量大的话可以
	 */
	@Transactional
	public void batchSave(List<E> entitys, int numberOfBatch) {
		numberOfBatch = (numberOfBatch < 30) ? 30 : numberOfBatch;
		int count = 1;
		try {
			for (E entity : entitys) {
				if (entity.getId() > 0) {
					entityManager.merge(entity);
				} else {
					entityManager.persist(entity);
				}
				if (count % numberOfBatch == 0) {
					entityManager.flush();
					entityManager.clear();
				}
				count++;
			}
		} catch (Exception e) {
			throw new ServiceException("保存出错：" + e.getMessage(), e);
		}
	}

	/**
	 * 保存实体
	 */
	@Transactional(readOnly = false)
	public void save(E entity) {
		if (entity instanceof OperateEntity && null != UserUtil.getUser()) {
			OperateEntity entity2 = (OperateEntity) entity;
			if (null == entity.getId()) {
				entity2.setCreateTime(new Date());
				entity2.setCreateUserId(UserUtil.getUser().getId());
				entity2.setCreateUserLongName(UserUtil.getUser().getLoginName());
			} else {
				entity2.setModifyTime(new Date());
				entity2.setModifyUserId(UserUtil.getUser().getId());
				entity2.setModifyUserLongName(UserUtil.getUser().getLoginName());
			}
		}
		try {
			getDao().save(entity);
		} catch (Exception e) {
			throw new ServiceException("保存出错：" + e.getMessage(), e);
		}
	}

	/**
	 * 删除实体
	 */
	@Transactional(readOnly = false)
	public void delete(final Long id) {
		try {
			getDao().delete(id);
		} catch (Exception e) {
			throw new ServiceException("删除出错：" + e.getMessage(), e);
		}
	}

	/**
	 * 删除实体，内部为逐个删除
	 */
	@Transactional(readOnly = false)
	public void deletes(final List<Long> ids) {
		if (null == ids || ids.isEmpty()) {
			return;
		}
		try {
			for (Long id : ids) {
				getDao().delete(id);
			}
		} catch (Exception e) {
			throw new ServiceException("删除出错：" + e.getMessage(), e);
		}
	}

	/**
	 * 获取全部的实体
	 */
	public List<E> getAll() {
		return (List<E>) getDao().findAll();
	}

	/**
	 * 分页查询的实现
	 */
	public JPage<E> search(Map<String, Object> searchParams, JPage<E> jPage) {
		PageRequest springPageRequest = FilterUtil.buildPageRequest(jPage);
		Specification<E> spec = FilterUtil.builderSpecification(searchParams, this.genericClassE);
		Page<E> page = this.getDao().findAll(spec, springPageRequest);
		return FilterUtil.pageToJPage(page, jPage);
	}

}
